First, we'll connect to the niPOD database.

Note: if you have the 32 bit version of ACE installed, you must use a 32 bit python to do this. See http://stackoverflow.com/questions/25820698/how-do-i-import-an-accdb-file-into-python-and-use-the-data


In [1]:
import pyodbc

driver = '{Microsoft Access Driver (*.mdb, *.accdb)}'
db_path = 'C:\\niPOD\\Database\\niPOD.accdb'
conn = pyodbc.connect('DRIVER={};DBQ={}'.format(driver,db_path))
cursor = conn.cursor()

Tada!

OK, now let's see what interesting tables we have.


In [2]:
table_list = []
for row in cursor.tables():
    if 'SYSTEM' not in row[3]:
        table_list.append(row[2])

print 'Tables:'
print '  ' +'\n  '.join(table_list)


Tables:
  Adaptor
  CV
  CV_Data
  DesignType
  Impedance
  Manufacture
  Mapping
  MeasurementType
  Paste Errors
  ProbeDiary
  ProbeInventory
  ProbePackage
  ProbeSpec
  ProbeType
  Status

In [3]:
for table in table_list:
    cursor.execute("select * from [%s]" % table)
    columns = [column[0] for column in cursor.description]
    n = len(list(cursor))
    print "%s (%i rows)" % (table,n)
    print '  ' +'\n  '.join(columns)


Adaptor (0 rows)
  AdaptorID
  AdaptorName
  CalibrationMultiple
CV (0 rows)
  DiaryID
  ChargeCapacity
  ChannelNumber
CV_Data (0 rows)
  DiaryID
  Voltage
  Current
  ChannelNumber
DesignType (3 rows)
  DesignTypeID
  DesignType
  DefaultNumShank
  DefaultNumChannel
  DefaultNumSitePerShank
  DefaultSiteArea
  DefaultShankSpace
  DefaultShankHeight
  DefaultShankWidth
  DefaultDisplaySiteSize
  DefaultDisplaySiteSpacing
  DefaultShankStartingXLocation
  DefaultShankStartingYLocation
  DefaultDisplaySiteFontSize
  DefaultTextBoxWidth
  DefaultTextBoxPhaseWidth
  DefaultFirstChannelYSpacing
  DefaultTextBoxHeight
  DefaultTetrodeOffsetUp
  DefaultTetrodeOffsetRight
  DefaultTetrodeOffsetLeft
  DefaultExtraNoteStartingXLocation
Impedance (0 rows)
  DiaryID
  Frequency
  ChannelNumber
  ZMag
  ZPhase
  Defective
  StatusID
Manufacture (1 rows)
  ManufactureID
  Description
Mapping (11333 rows)
  PackageID
  DeviceChannelNum
  ConnectorChannelNum
  SiteOrientationNum
MeasurementType (4 rows)
  MeasurementTypeID
  Description
Paste Errors (17 rows)
  F1
  F2
  F3
  F4
ProbeDiary (0 rows)
  ProbeID
  DiaryID
  DiaryDate
  MeasurementTypeID
  Comments
  SystemParameters
  Parameter1
  Parameter2
ProbeInventory (3 rows)
  ProbeID
  NickName
  DesignID
  LastUsed
  SerialNumber
  CountOfDefectiveSite
ProbePackage (399 rows)
  PackageID
  PackageName
  N2TID
ProbeSpec (1440 rows)
  DesignID
  ProbeTypeID
  ManufactureID
  PackageID
  N2TProductID
  DesignName
  DesignTypeID
  NumShank
  NumChannel
  NumSitePerShank
  SiteArea
  ShankSpace
  ShankHeight
  ShankWidth
  DisplaySiteSize
  DisplaySiteSpacing
  ShankStartingXLocation
  ShankStartingYLocation
  DisplaySiteFontSize
  TextBoxWidth
  TextBoxPhaseWidth
  FirstChannelYSpacing
  TextBoxHeight
  TetrodeOffsetUp
  TetrodeOffsetRight
  TetrodeOffsetLeft
  TrueShankLength
  TrueSiteSpacing
  OtherParameters
ProbeType (4 rows)
  ProbeTypeID
  ProbeType
Status (5 rows)
  StatusID
  StatusColor
  DisplayAlertCode

So a few of these are simply lookup tables. Many are empty. ProbeSpec, ProbePackage, and Mapping are the big ones. I'm guessing those have what we want.

Let's write up a little function to query them and drop the rows into a pandas dataframe.


In [4]:
import pandas as pd
def get_df(table,cursor):
    cursor.execute("select * from [%s]" % table)
    columns = [column[0] for column in cursor.description]

    results = []
    for row in cursor.fetchall():
        results.append(dict(zip(columns, row)))

    return pd.DataFrame(results)

OK, let's see what's in one of these tables now.


In [5]:
df = get_df('ProbeSpec',cursor)
print len(df)
df.head()


1440
Out[5]:
DesignID DesignName DesignTypeID DisplaySiteFontSize DisplaySiteSize DisplaySiteSpacing FirstChannelYSpacing ManufactureID N2TProductID NumChannel ... ShankWidth SiteArea TetrodeOffsetLeft TetrodeOffsetRight TetrodeOffsetUp TextBoxHeight TextBoxPhaseWidth TextBoxWidth TrueShankLength TrueSiteSpacing
0 1 A16x1-3mm-100-125-413-HC16_21mm 3 8.25 30 8 80 1 3167 16 ... 50 413 5 3 5 15 30 30 3 100
1 2 A16x1-3mm-100-125-413-HP16_21mm 3 8.25 30 8 80 1 3168 16 ... 50 413 5 3 5 15 30 30 3 100
2 3 A16x1-3mm-100-125-413-MRCM16 3 8.25 30 8 80 1 3171 16 ... 50 413 5 3 5 15 30 30 3 100
3 4 A16x1-3mm-100-125-413-Z16 3 8.25 30 8 80 1 3164 16 ... 50 413 5 3 5 15 30 30 3 100
4 5 A16x1-3mm-100-125-703-A16 3 8.25 30 8 80 1 3172 16 ... 50 703 5 3 5 15 30 30 3 100

5 rows × 29 columns

That looks like what we want. 1440 rows with DesignName as one of the columns and a bunch of data on the number of channels, shanks, etc.

Let's pull all of the non-empty tables down and drop them into CSV.


In [6]:
for table in table_list:
    df = get_df(table,cursor)
    if len(df)>0:
        df.to_csv('NiPOD-%s.csv' % table, 
                  encoding='utf-8',
                 index=False)

In [7]:
%ls *.csv


 Volume in drive C has no label.
 Volume Serial Number is E01E-DC6E

 Directory of C:\Users\jkiggins\Dropbox\Projects\niPOD-database

07/07/2015  08:11 PM               694 NiPOD-DesignType.csv
07/07/2015  08:11 PM                54 NiPOD-Manufacture.csv
07/07/2015  08:11 PM           146,736 NiPOD-Mapping.csv
07/07/2015  08:11 PM                83 NiPOD-MeasurementType.csv
07/07/2015  08:11 PM               358 NiPOD-Paste Errors.csv
07/07/2015  08:11 PM               111 NiPOD-ProbeInventory.csv
07/07/2015  08:11 PM             8,312 NiPOD-ProbePackage.csv
07/07/2015  08:11 PM           306,717 NiPOD-ProbeSpec.csv
07/07/2015  08:11 PM                92 NiPOD-ProbeType.csv
07/07/2015  08:11 PM               131 NiPOD-Status.csv
              10 File(s)        463,288 bytes
               0 Dir(s)  107,966,586,880 bytes free

Beautiful. Next, we'll see if we can build KlustaKwik geometries from the data in this database.